package bitmap;

import java.io.*;
import java.lang.*;

import btree.*;
import bufmgr.*;
import diskmgr.*;
import global.*;
import heap.*;

import columnar.*;

///**
// * interface of PageUsedBytes
// */
//interface PageUsedBytes
//{
//  int DIR_PAGE_USED_BYTES = 8 + 8;
//  int FIRST_PAGE_USED_BYTES = DIR_PAGE_USED_BYTES + 4;
//}

public class BitMapFile extends IndexFile implements GlobalConst {
	private BitMapHeaderPage headerPage;
	private PageId headerPageId;
	private String dbname;
	// private RandomAccessFile fp;
	// private int num_pages;
	// private String name;
	private BMPage bmPage;
	private BMPage tempPage;
	private PageId pageid;

	private final static int MAGIC0 = 1989;

	private void add_file_entry(String fileName, PageId pageno)
			throws AddFileEntryException {
		try {
			SystemDefs.JavabaseDB.add_file_entry(fileName, pageno);
		} catch (Exception e) {
			e.printStackTrace();
			throw new AddFileEntryException(e, "");
		}
	}

	private void delete_file_entry(String filename)
			throws DeleteFileEntryException {
		try {
			SystemDefs.JavabaseDB.delete_file_entry(filename);
		} catch (Exception e) {
			e.printStackTrace();
			throw new DeleteFileEntryException(e, "");
		}
	}

	private PageId get_file_entry(String filename) throws GetFileEntryException {
		try {
			return SystemDefs.JavabaseDB.get_file_entry(filename);
		} catch (Exception e) {
			e.printStackTrace();
			throw new GetFileEntryException(e, "");
		}
	}

	// constructor
	// BitMapFile class; an index file with given filename should already exist,
	// then this opens it.
	public BitMapFile(String filename) throws GetFileEntryException,
			ConstructPageException {

		headerPageId = get_file_entry(filename);

		headerPage = new BitMapHeaderPage(headerPageId);
		dbname = new String(filename);
		/*
		 * 
		 * - headerPageId is the PageId of this BitMapFile's header page; -
		 * headerPage, headerPageId valid and pinned - dbname contains a copy of
		 * the name of the database
		 */
	}

	// BitMapFile class; an index file with given filename should not already
	// exist; this creates the BitMap file from scratch
	public BitMapFile(String filename, Columnarfile columnfile, int ColumnNo,
			ValueClass value) throws GetFileEntryException,
			ConstructPageException, IOException, AddFileEntryException,
			InvalidTupleSizeException, UnpinPageException, PinPageException,
			PageUnpinnedException, InvalidFrameNumberException,
			HashEntryNotFoundException, ReplacerException,
			FieldNumberOutOfBoundException, InvalidTypeException,
			IteratorException, HashOperationException, PageNotReadException,
			BufferPoolExceededException, PagePinnedException, BufMgrException,
			InvalidSlotNumberException, HFException, HFBufMgrException,
			HFDiskMgrException, SpaceNotAvailableException {
		headerPageId = get_file_entry(filename);
		if (headerPageId == null) // file not exist
		{
			headerPage = new BitMapHeaderPage();
			headerPageId = headerPage.getPageId();
			add_file_entry(filename, headerPageId);

			headerPage.set_magic0(MAGIC0);
			headerPage.set_rootId(new PageId(INVALID_PAGE));
			// headerPage.set_keyType((short)value); //store the type of value
			// headerPage.set_maxKeySize(value.length); //store the length of
			// value
			// headerPage.set_deleteFashion(delete_fashion);
			// headerPage.setType(NodeType.);
		} else {
			headerPage = new BitMapHeaderPage(headerPageId);
		}
		dbname = new String(filename);

		// pageid = new PageId(headerPage.getCurPage().pid + 1);
		// bmPage = new BMPage(pinPage(pageid));
		// bmPage.init(pageid, bmPage);
		bmPage = new BMPage();
		bmPage.setPrevPage(headerPageId);
		headerPage.set_rootId(bmPage.getCurPage());
		Scan cscan;
		cscan = columnfile.openColumnScan(ColumnNo);
		RID rid = new RID();
		Tuple tuple = new Tuple();
		AttrType[] type = columnfile.getAttrTypes();
		tuple = cscan.getNext(rid);
		while (tuple != null) {
			byte[] record = new byte[MAX_SPACE - BMPage.DPFIXED];
			// pageid = new PageId(bmPage.getCurPage().pid + 1);
			// tempPage = new BMPage(pinPage(pageid));
			// tempPage.init(pageid, tempPage);
			for (int i = 0; i < record.length; i++) {
				for (int j = 0; j < 8; j++) {
					Columnarfile.SetOneColumnTupleHeader(tuple, type[ColumnNo]);
					if (type[ColumnNo].attrType == AttrType.attrInteger) {
						if (value.toString().equals("" + tuple.getIntFld(1))) {
							record[i] += 1 << j;
							System.out.print(1);
						} else {
							System.out.print(0);
						}
					} else if (type[ColumnNo].attrType == AttrType.attrString) {
						if (value.toString().equals(tuple.getStrFld(1))) {
							record[i] += 1 << j;
							System.out.print(1);
						} else {
							System.out.print(0);
						}
					}

					if ((tuple = cscan.getNext(rid)) == null) {
						byte[] temp = new byte[i + 1];
						System.arraycopy(record, 0, temp, 0, i + 1);
						bmPage.writeBMPageArray(temp);
						unpinPage(bmPage.getCurPage());
						cscan.closescan();
						this.close();
						return;
					}
				}
				System.out.print(" ");
			}
			System.out.print("\n");
			bmPage.writeBMPageArray(record);
			tempPage = new BMPage();
			tempPage.setPrevPage(bmPage.getCurPage());
			bmPage.setNextPage(tempPage.getCurPage());
			unpinPage(bmPage.getCurPage());
			bmPage = tempPage;
		}
	}

	/**
	 * Close the bit map file. Unpin header page.
	 * 
	 * @exception PageUnpinnedException
	 *                error from the lower layer
	 * @exception InvalidFrameNumberException
	 *                error from the lower layer
	 * @exception HashEntryNotFoundException
	 *                error from the lower layer
	 * @exception ReplacerException
	 *                error from the lower layer
	 */
	public void close() throws PageUnpinnedException,
			InvalidFrameNumberException, HashEntryNotFoundException,
			ReplacerException {
		if (headerPage != null) {
			SystemDefs.JavabaseBM.unpinPage(headerPageId, true);
			headerPage = null;
		}
	}

	/**
	 * Destroy entire bit map file.
	 * 
	 * @exception IOException
	 *                error from the lower layer
	 * @exception IteratorException
	 *                iterator error
	 * @exception UnpinPageException
	 *                error when unpin a page
	 * @exception FreePageException
	 *                error when free a page
	 * @exception DeleteFileEntryException
	 *                failed when delete a file from DM
	 * @exception ConstructPageException
	 *                error in BT page constructor
	 * @exception PinPageException
	 *                failed when pin a page
	 */
	public void destroyFile() throws IOException, IteratorException,
			UnpinPageException, FreePageException, DeleteFileEntryException,
			ConstructPageException, PinPageException {
		if (headerPage != null) {
			PageId pgId = headerPage.get_rootId();
			// if( pgId.pid != INVALID_PAGE)
			// _destroyFile(pgId);

			unpinPage(headerPageId);
			freePage(headerPageId);
			delete_file_entry(dbname);
			headerPage = null;
		}
	}

	// access method to data member
	public BitMapHeaderPage getHeaderPage() {
		return headerPage;
	}

	public void Insert(final KeyClass data, final RID rid) {
	}

	public boolean Delete(final KeyClass data, final RID rid) {
		return true;
	}

	// set the entry at the given position to 0 ?????????
	public boolean Delete(int position) {

		// bitMap[position] = 0;
		return true;
	}

	// set the entry at the given position to 1 ??????????
	public boolean Insert(int position) {

		// bitMap[position] = 1;
		return true;

	}

	private Page pinPage(PageId pageno) throws PinPageException {
		try {
			Page page = new Page();
			SystemDefs.JavabaseBM.pinPage(pageno, page, false/* Rdisk */);
			return page;
		} catch (Exception e) {
			e.printStackTrace();
			throw new PinPageException(e, "");
		}
	}

	private void unpinPage(PageId pageno) throws UnpinPageException {
		try {
			SystemDefs.JavabaseBM.unpinPage(pageno, true /* = DIRTY */);
		} catch (Exception e) {
			e.printStackTrace();
			throw new UnpinPageException(e, "");
		}
	}

	private void freePage(PageId pageno) throws FreePageException {
		try {
			SystemDefs.JavabaseBM.freePage(pageno);
		} catch (Exception e) {
			e.printStackTrace();
			throw new FreePageException(e, "");
		}

	}
}
